package com.jc.common.redis.trans;

import java.util.List;

public abstract class RedisTransacitonTemplate {
	private RedisTransaction redisTransaction;

	public RedisTransacitonTemplate(RedisTransaction redisTransaction) {
		this.redisTransaction = redisTransaction;
	}

	/**
	 * 事务前的准备(watch后执行的代码)
	 * @return
	 */
	protected abstract boolean prepare();

	/**
	 * 在事务执行 (mutil 和 exec 中间执行的代码)
	 * @param ts
	 * @param retryable
	 */
	protected abstract void doInTrans(RedisTransactionStatus ts);
			

	/**
	 * 执行
	 * @param retryable
	 * @param keys
	 * @return
	 */
	public List<Object> execute(Retryable retryable, String... keys) {
		RedisTransactionStatus ts = redisTransaction.init(keys); // begin transaction

		boolean isReady = false;
		try {
			isReady = prepare();
		} catch (Throwable t) {
			redisTransaction.destroy(ts);
			return null;
		}

		// 未准备好，不需要执行
		if (!isReady) {
			redisTransaction.destroy(ts);
			return null;
		}

		redisTransaction.begin(ts);
		List<Object> resultList = null;
		try {
			doInTrans(ts);
			resultList = redisTransaction.commit(ts);
		} catch (Throwable t) {
			redisTransaction.rollback(ts);
		}

		// 重试
		if (resultList == null || resultList.size() == 0) {
			if (retryable != null && retryable.retry()) {
				resultList = execute(retryable, keys);
			}
		}
		return resultList;
	}
}
